#ifndef _BUOLA_MEMORY_CMANAGEDMEMORY_H_
#define _BUOLA_MEMORY_CMANAGEDMEMORY_H_

#include <buola/buola.h>

namespace buola {

//tAlgorithm must be standard layout!
    
template<typename tAlgorithm>
class CManagedMemory : public UUncopiable
{
    static const uint32_t cManagerMagic=0x19570604;

    struct SManager
    {
        SManager(std::size_t pSize)
            :   mMagic(cManagerMagic)
            ,   mAlgorithm(pSize,static_cast<void*>(this),sizeof(*this))
        {}

        uint32_t mMagic;
        tAlgorithm mAlgorithm;
    };
    
public:
    CManagedMemory()
        :   mManager(nullptr)
    {}

    void Init(bool pCreate,void *pAddress,std::size_t pSize)
    {
        assert(!mManager);
        if(pCreate)
        {
            mManager=new(pAddress) SManager(pSize);
        }
        else
        {
            mManager=static_cast<SManager*>(pAddress);
            if(mManager->mMagic!=cManagerMagic)
            {
                throw XData("invalid magic opening managed memory");
            }
        }
        mSize=pSize;
    }

    std::size_t size() const
    {
        return mSize;
    }

    std::size_t FreeMemory() const
    {
        return mManager->mAlgorithm.FreeMemory();
    }

    bool empty() const
    {
        return mManager->mAlgorithm.empty();
    }

    void *Allocate(std::size_t pNBytes)
    {
        return mManager->mAlgorithm.Allocate(pNBytes);
    }

    void *Allocate(std::size_t pNBytes,std::nothrow_t pNoThrow)
    {
        return mManager->mAlgorithm.Allocate(pNBytes,pNoThrow);
    }

    void Deallocate(void *pAddress)
    {
        return mManager->mAlgorithm.Deallocate(pAddress);
    }

private:
    SManager *mManager;
    std::size_t mSize;
};

/*namespace buola*/ }

#endif
